# -*- coding: utf-8 -*-
"""
@Time    : 2022/8/29 16:17
@Author  : huanghuang
"""
import time
import uuid
import datetime
from typing import Union

from aioredis import Redis


LETTER_ARRAY = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
                "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U",
                "V", "W", "X", "Y", "Z",
                "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u",
                "v", "w", "x", "y", "z",
                ]


def get_short_uuid(prefix=""):
    uid = str(uuid.uuid4()).replace("-", "")
    buffer = []
    for i in range(0, 8):
        start = i * 4
        end = start + 4
        val = int(uid[start:end], 16)
        buffer.append(LETTER_ARRAY[val % 62])
    return f"{prefix}{''.join(buffer)}"


def get_id_with_date_info(prefix=""):
    return f"{prefix}{datetime.datetime.now().strftime('%y%m%d%H%M%S')}"


def generate_sn(prefix="", suffix=""):
    """
    根据前缀和后缀 生成sn
    :param prefix:
    :param suffix:
    :return:
    """
    return f"{prefix}{datetime.datetime.now().strftime('%y%m%d%H%M%S')}{suffix}"


def zfill_0(n: Union[int, str], digits: int = 6):
    return str(n).zfill(digits)


async def generate_sn_with_redis(prefix="", suffix="", redis: Redis = None):
    from common.g.g import G_REDIS
    redis = redis or G_REDIS
    res = await redis.incr(f"{datetime.datetime.now().date().strftime('%Y%m%d')}")
    return f"{get_id_with_date_info(prefix)}{zfill_0(res)}{suffix}"


class InvalidSystemClock(Exception):
    ...


class IdWorkerConfig:
    def __init__(self, worker_id_bit, data_center_id_bit, sequence_bit, sys_starttimestamp):
        self.worker_id_bit = worker_id_bit
        self.data_center_id_bit = data_center_id_bit
        self.sequence_bit = sequence_bit
        self.sys_starttimestamp = sys_starttimestamp

        self.max_worker_id = -1 ^ (-1 << worker_id_bit)
        self.max_data_center_id = -1 ^ (-1 << data_center_id_bit)
        self.worker_id_shift = self.sequence_bit
        self.data_center_id_shift = self.sequence_bit + self.worker_id_bit
        self.timestamp_left_shift = self.sequence_bit + self.worker_id_bit + self.data_center_id_bit
        self.sequence_mask = -1 ^ (-1 << self.sequence_bit)


class IdWorker:

    def __init__(self, idworker_config: IdWorkerConfig, datacenter_id, worker_id, sequence=0):
        from common.g.g import G_LOGGER

        G_LOGGER.info(f"data_center_id={datacenter_id}, worker_id={worker_id}")
        self.config = idworker_config
        if worker_id > self.config.max_worker_id or worker_id < 0:
            raise ValueError('worker_id值越界')

        if datacenter_id > self.config.max_data_center_id or datacenter_id < 0:
            raise ValueError('datacenter_id值越界')

        self.worker_id = worker_id
        self.datacenter_id = datacenter_id
        self.sequence = sequence

        self.last_timestamp = -1  # 上次计算的时间戳

    def _gen_ms_timestamp(self):
        """
        生成整数时间戳 毫秒
        :return:int timestamp
        """
        return int(time.time() * 1000)

    def get_id(self):
        """
        获取新ID
        :return:
        """
        timestamp = self._gen_ms_timestamp()

        # 时钟回拨
        if timestamp < self.last_timestamp:
            raise InvalidSystemClock

        if timestamp == self.last_timestamp:
            self.sequence = (self.sequence + 1) & self.config.sequence_mask
            if self.sequence == 0:
                timestamp = self._next_millis(self.last_timestamp)
        else:
            self.sequence = 0

        self.last_timestamp = timestamp

        new_id = ((timestamp - self.config.sys_starttimestamp) << self.config.timestamp_left_shift) | (self.datacenter_id << self.config.data_center_id_shift) | \
                 (self.worker_id << self.config.worker_id_shift) | self.sequence
        return new_id

    def _next_millis(self, last_timestamp):
        """
        下一毫秒
        """
        timestamp = self._gen_ms_timestamp()
        while timestamp <= last_timestamp:
            timestamp = self._gen_ms_timestamp()
        return timestamp


def ten_to_any(num, h):
    l = []
    while True:
        # 取商
        s = num // h
        # 取余数
        tmp = num % h
        l.append(LETTER_ARRAY[tmp])
        if s == 0:
            break
        num = s
    l.reverse()
    l = [str(each) for each in l]
    return "".join(l)
